/**
 * 事件监听帮助类，用于处理各种DOM事件的监听和管理
 * 
 * 主要功能：
 * - 封装DOM事件的添加和移除逻辑
 * - 提供对特殊事件（如hover）的处理
 * - 支持事件监听器的统一管理和清理
 * 
 * @example
 * ```typescript
 * const eventHelper = new EventListenerHelper();
 * 
 * // 添加hover事件监听
 * eventHelper.addHoverListener(element, {
 *   onMouseEnter: () => {
 *     // 鼠标进入时的处理逻辑
 *   },
 *   onMouseLeave: () => {
 *     // 鼠标离开时的处理逻辑
 *   }
 * });
 * 
 * // 添加普通事件监听
 * eventHelper.addListener(element, 'click', () => {
 *   // 点击事件处理逻辑
 * });
 * 
 * // 清理指定元素的所有事件监听
 * eventHelper.clear(element);
 * ```
 * @module EventListenerHelper
 */

/**
 * 事件监听器存储结构
 */
interface ElementListeners {
  [event: string]: EventListenerOrEventListenerObject[];
}

/**
 * Hover事件监听器选项
 */
export interface HoverListenerOptions {
  /** 鼠标进入事件处理函数 */
  onMouseEnter: EventListenerOrEventListenerObject;
  /** 鼠标离开事件处理函数 */
  onMouseLeave: EventListenerOrEventListenerObject;
  /** 是否使用捕获阶段 */
  useCapture?: boolean;
}

/**
 * 普通事件监听器选项
 */
export interface ListenerOptions {
  /** 是否使用捕获阶段 */
  useCapture?: boolean;
}

export class EventListenerHelper {
  /**
   * 存储元素与其事件监听器的映射关系
   * @private
   */
  private __elementListeners: WeakMap<Element, ElementListeners>;

  /**
   * 创建事件监听帮助类实例
   * @constructor
   */
  constructor() {
    this.__elementListeners = new WeakMap<Element, ElementListeners>();
  }

  /**
   * 获取指定元素的事件监听器存储对象
   * @private
   * @param {Element} element - DOM元素
   * @returns {ElementListeners} 事件监听器存储对象
   */
  private __getElementListeners(element: Element): ElementListeners {
    if (!this.__elementListeners.has(element)) {
      this.__elementListeners.set(element, {});
    }
    return this.__elementListeners.get(element)!;
  }

  /**
   * 添加hover事件监听器（实际上是mouseenter和mouseleave事件的组合）
   * @param {Element} element - DOM元素
   * @param {HoverListenerOptions} options - hover事件监听选项
   * @returns {void}
   */
  public addHoverListener(element: Element, options: HoverListenerOptions): void {
    const { onMouseEnter, onMouseLeave, useCapture = false } = options;

    // 添加mouseenter事件监听
    this.addListener(element, 'mouseenter', onMouseEnter, { useCapture });
    
    // 添加mouseleave事件监听
    this.addListener(element, 'mouseleave', onMouseLeave, { useCapture });
  }

  /**
   * 添加普通事件监听器
   * @param {Element} element - DOM元素
   * @param {string} event - 事件名称
   * @param {EventListenerOrEventListenerObject} listener - 事件处理函数
   * @param {ListenerOptions} [options] - 事件监听选项
   * @returns {void}
   */
  public addListener(
    element: Element,
    event: string,
    listener: EventListenerOrEventListenerObject,
    options: ListenerOptions = {}
  ): void {
    const { useCapture = false } = options;
    const elementListeners = this.__getElementListeners(element);

    // 确保事件类型对应的监听器数组存在
    if (!elementListeners[event]) {
      elementListeners[event] = [];
    }

    // 添加事件监听器到DOM元素
    element.addEventListener(event, listener, useCapture);
    
    // 保存事件监听器引用以便后续移除
    elementListeners[event].push(listener);
  }

  /**
   * 移除指定元素的指定事件的所有监听器
   * @param {Element} element - DOM元素
   * @param {string} event - 事件名称
   * @param {boolean} [useCapture=false] - 是否使用捕获阶段
   * @returns {void}
   */
  public removeListeners(element: Element, event: string, useCapture: boolean = false): void {
    if (!this.__elementListeners.has(element)) {
      return;
    }

    const elementListeners = this.__elementListeners.get(element)!;
    const listeners = elementListeners[event];

    if (listeners) {
      // 移除DOM元素上的所有指定事件监听器
      listeners.forEach(listener => {
        element.removeEventListener(event, listener, useCapture);
      });
      
      // 清空存储的监听器数组
      delete elementListeners[event];
    }
  }

  /**
   * 移除指定元素的所有事件监听器
   * @param {Element} element - DOM元素
   * @returns {void}
   */
  public clear(element: Element): void {
    if (!this.__elementListeners.has(element)) {
      return;
    }

    const elementListeners = this.__elementListeners.get(element)!;
    
    // 移除所有事件类型的监听器
    Object.keys(elementListeners).forEach(event => {
      this.removeListeners(element, event);
    });
    
    // 从映射中删除元素
    this.__elementListeners.delete(element);
  }

  /**
   * 获取指定元素的指定事件的监听器数量
   * @param {Element} element - DOM元素
   * @param {string} [event] - 可选的事件名称，如果不指定则返回所有事件的监听器总数
   * @returns {number} 监听器数量
   */
  public getListenerCount(element: Element, event?: string): number {
    if (!this.__elementListeners.has(element)) {
      return 0;
    }

    const elementListeners = this.__elementListeners.get(element)!;
    
    if (event) {
      // 返回指定事件的监听器数量
      return elementListeners[event] ? elementListeners[event].length : 0;
    } else {
      // 返回所有事件的监听器总数
      return Object.values(elementListeners).reduce(
        (total, listeners) => total + listeners.length,
        0
      );
    }
  }
}

export default EventListenerHelper;